/*
服了，b站那个人也不讲解是怎么回事
[3]	https://www.bilibili.com/video/BV14T4y1d7hL/?share_source=copy_web&vd_source=d66304132142154d4d65897a9fb682c9 【Linux多线程4-3-2_条件变量实例】
*/

#include<stdio.h>
#include<pthread.h>


#define BUF_SIZE  5 //库存大小
#define PRODUCT_NUM 30 //产品生产总数

struct product_cons{
    int buf[BUF_SIZE]; //生产产品值
    pthread_mutex_t lock;//互斥锁 union共用体
    int read_pos,write_pos;//读写位置
    pthread_cond_t not_empty;//条件变量，非空
    pthread_cond_t not_full;//非满
}buffer;

//初始化
void init(struct product_cons *p){
    pthread_mutex_init(&p->lock,NULL);//互斥锁
    pthread_cond_init(&p->not_empty,NULL);//条件变量
    pthread_cond_init(&p->not_full,NULL);//条件变量
    p->read_pos=0;
    p->write_pos=0;
}

void finish(struct product_cons *p){
    pthread_mutex_destroy(&p->lock);//互斥锁
    pthread_cond_destroy(&p->not_empty);//条件变量
    pthread_cond_destroy(&p->not_full);//条件变量
    p->read_pos=0;
    p->write_pos=0;
}

//生产 一个数据到buffer
void put(struct product_cons *p,int data){
    /********************************************************/
    pthread_mutex_lock(&p->lock);
    if((p->write_pos+1)%BUF_SIZE==p->read_pos){
        printf("生产者");
        pthread_cond_wait(&p->not_full,&p->lock);
    }
    p->buf[p->write_pos]=data;
    p->write_pos++;

    if(p->write_pos>=BUF_SIZE){
        p->write_pos=0;
    }

    pthread_cond_signal(&p->not_empty);//告知消费者仓库有东西了
    pthread_mutex_unlock(&p->lock);
    /********************************************************/
}

//消费 一个数据从buffer
int get(struct product_cons *p){
    int data;
    /********************************************************/
    pthread_mutex_lock(&p->lock);
    if(p->read_pos==p->write_pos){
        printf("消费者");
        pthread_cond_wait(&p->not_empty,&p->lock);
    }   

    data=p->buf[p->read_pos];
    p->read_pos++;

    if(p->read_pos>=BUF_SIZE){
        p->read_pos=0;
    }
    pthread_cond_signal(&p->not_full);//告知生产者仓库有空位了
    pthread_mutex_unlock(&p->lock);
    /********************************************************/

    return data;
}

void *producer(void *data){
    int n;
    for(n=1;n<=50;+n){
        sleep(1);
        printf("正在生产产品，编号%d。。。\n",n);
        put(&buffer,n);
        printf("编号%d产品已放入仓库\n",n);
    }
    printf("生产停止\n");
    return NULL;
}

void *consumer(void *data){
    static int num=0;
    while(1){
        sleep(2);
        printf("从仓库取消费产品中。。。\n");
        num=get(&buffer);
        printf("获取产品成功\n");
        if(++num==PRODUCT_NUM){
            break;
        }
    }
    return NULL;
}

int main(){
    pthread_t th_a,th_b;
    void *retval;

    init(&buffer);

    pthread_create(&th_a,NULL,producer,0);
    pthread_create(&th_b,NULL,consumer,0);

    pthread_join(th_a,&retval);
    pthread_join(th_b,&retval);

    finish(&buffer);
}














